﻿using System;

namespace SharpAnalyzer.Entities
{

    // https://en.wikipedia.org/wiki/Halstead_complexity_measures
    public class HalsteadMetrics
    {
        public static readonly HalsteadMetrics GenericInstanceSetPropertyMetrics = new HalsteadMetrics()
        {
            NumOperands = 5,
            NumOperators = 3,
            NumUniqueOperands = 4,
            NumUniqueOperators = 3
        };
        public static readonly HalsteadMetrics GenericStaticSetPropertyMetrics = new HalsteadMetrics()
        {
            NumOperands = 4,
            NumOperators = 3,
            NumUniqueOperands = 3,
            NumUniqueOperators = 3
        };
        public static readonly HalsteadMetrics GenericInstanceGetPropertyMetrics = new HalsteadMetrics()
        {
            NumOperands = 3,
            NumOperators = 2,
            NumUniqueOperands = 3,
            NumUniqueOperators = 2
        };
        public static readonly HalsteadMetrics GenericStaticGetPropertyMetrics = new HalsteadMetrics()
        {
            NumOperands = 2,
            NumOperators = 1,
            NumUniqueOperands = 2,
            NumUniqueOperators = 1
        };

        // N2
        public int NumOperands { get; internal set; }

        // n2
        public int NumUniqueOperands { get; internal set; }

        // N1
        public int NumOperators { get; internal set; }

        // n1
        public int NumUniqueOperators { get; internal set; }

        public int GetLength()
        {
            return checked(this.NumOperators + this.NumOperands);
        }

        public int GetVocabulary()
        {
            return checked(this.NumUniqueOperators + this.NumUniqueOperands);
        }

        public double GetDifficulty()
        {
            return (double)this.NumUniqueOperators / 2.0 * ((double)this.NumOperands / (double)this.NumUniqueOperands);
        }

        public double? GetVolume()
        {
            double a = (double)this.GetVocabulary();
            double num = (double)this.GetLength();
            if (a == 0.0)
                return null;

            return num * Math.Log(a, 2.0);
        }

        public double? GetEffort()
        {
            double difficulty = this.GetDifficulty();
            double? volume = this.GetVolume();
            if (!volume.HasValue)
                return null;

            return difficulty * volume.Value;
        }

        // Number of delivered bugs
        public double? GetBugs()
        {
            double? volume = this.GetVolume();
            if (!volume.HasValue)
                return null;

            return volume.Value / 3000.0;
        }

        // Time required to program
        public double? TimeRequired()
        {
            double? effort = this.GetEffort();
            if (!effort.HasValue)
                return null;

            return effort / 18.0;
        }
    }
}
